package grpc_proxy_middleware

import (
	"context"
	"strings"

	"github.com/pkg/errors"
	"github.com/youkelike/gateway/dao"
	"github.com/youkelike/gateway/public"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

// jwt auth token
func GrpcJwtAuthTokenMiddleware(serviceDetail *dao.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		// 这里拿到的是 context 中经过深拷贝后的数据
		md, ok := metadata.FromIncomingContext(ss.Context())
		if !ok {
			return errors.New("miss metadata from context")
		}
		authToken := ""
		auths := md.Get("authorization")
		if len(auths) > 0 {
			authToken = auths[0]
		}
		// fmt.Println(auths)
		token := strings.ReplaceAll(authToken, "Bearer ", "")
		appMatched := false
		var appStr string
		if token != "" {
			claims, err := public.JwtDecode(token)
			if err != nil {
				return errors.WithMessage(err, "JwtDecode")
			}
			// fmt.Println(claims.Issuer)
			appList := dao.AppManagerHandler.GetAppList()
			for _, appInfo := range appList {
				if appInfo.AppID == claims.Issuer {
					// md.Set("app", public.Obj2Json(appInfo))
					appStr = public.Obj2Json(appInfo)
					appMatched = true
					break
				}
			}
		}
		if serviceDetail.AccessControl.OpenAuth == 1 && !appMatched {
			return errors.New("not match valid app")
		}

		// 在处理器之间传递数据只能用 context，不能用 md.Set，
		ctx := context.WithValue(ss.Context(), "appInfo", appStr)

		if err := handler(srv, &wrappedSS{ServerStream: ss, Ctx: ctx}); err != nil {
			// log.Printf("GrpcJwtAuthTokenMiddleware failed with error %v\n", err)
			return err
		}
		return nil
	}
}

type wrappedSS struct {
	grpc.ServerStream
	Ctx context.Context
}

func (w *wrappedSS) Context() context.Context {
	return w.Ctx
}
